
Imports System.IO
Imports std
Imports storoomc

Public Class slice
    Inherits _slice(Of atom)

    Private slicesize As UInt64

    Public Class atom
        Public start As UInt64 = 0
        Public valuestart As UInt64 = 0
        Public valuelength As UInt64 = 0

        Public Function [end]() As UInt64
            Return valuestart + valuelength
        End Function

        Public Function length() As UInt64
            Return [end]() - start
        End Function
    End Class

    Public Sub New()
        MyBase.New()
        slicesize = read_slicesize()
    End Sub

    Protected Overrides Function fullImpl() As Boolean
        Return MyBase.fullImpl() OrElse stream().Length() >= slicesize
    End Function

    Protected Overrides Function appendImpl(ByVal atom As atom, ByVal buff As bytes) As Boolean
        If stream().Length < atom.end() Then
            raiseError("cannot get enough data from slice " + filename() + ", invalid slice file.", _
                       errorHandle.errorType.exclamation)
            Return False
        Else
            'read existing data and prepare for new one
            Dim valueBuff As bytes = Nothing
            valueBuff = New bytes()
            valueBuff.size = atom.valuelength
            stream().Position = atom.valuestart
            If stream.Read(+valueBuff, 0, atom.valuelength) < atom.valuelength Then
                raiseError("cannot read enough data from stream " + filename() + ", invalid slice file.", _
                           errorHandle.errorType.exclamation)
                Return False
            End If
            assert(stream().Position = atom.end(), "stream.Position <> atom.end()")
            valueBuff += buff
            atom.valuelength += buff.size()

            'move other data
            If stream().Length > atom.end() Then
                Dim movelength As UInt64
                movelength = stream().Length() - atom.end()
                If streammove(stream(), atom.end(), atom.end() + buff.size(), movelength) <> movelength Then
                    raiseError("cannot move enough data from stream " + filename() + ", invalid slice file." _
                                , errorHandle.errorType.exclamation)
                    Return False
                End If

                Dim action As traversal_atoms_action = Function(a As atom) As Boolean
                                                           If a.start > atom.start Then
                                                               a.start += buff.size()
                                                               a.valuestart += buff.size()
                                                           End If
                                                           Return True
                                                       End Function
                traversal_atoms(action)
            End If

            writer().BaseStream.Position = atom.valuestart
            writer().Write(Convert.ToUInt64(atom.valuelength))
            writer().Write(+valueBuff)
            Return True
        End If
    End Function

    Protected Overrides Function atom_ctor() As atom
        Return New atom()
    End Function

    Protected Overrides Function closeImpl() As Boolean
        Return True
    End Function

    Protected Overrides Function deleteImpl(ByVal atom As atom) As Boolean
        Dim movelen As UInt64
        movelen = stream().Length() - atom.end()
        If movelen < 0 Then
            raiseError("cannot get enough data from slice " + filename() + ", invalid slice file.", _
                       errorHandle.errorType.exclamation)
            Return False
        ElseIf movelen > 0 Then
            If streammove(stream(), atom.end(), atom.start, movelen) <> movelen Then
                raiseError("cannot move enough data from stream " + filename() + ", invalid slice file." _
                           , errorHandle.errorType.exclamation)
                Return False
            End If

            Dim action As traversal_atoms_action = Function(a As atom) As Boolean
                                                       If a.start > atom.start Then
                                                           a.start -= atom.length()
                                                           a.valuestart -= atom.length()
                                                       End If
                                                       Return True
                                                   End Function
            traversal_atoms(action)
        End If
        stream.SetLength(atom.start + movelen)

        Return True
    End Function

    Protected Overrides Function filter_slicetype_value() As String
        Return configNaming.filter.value.slicetype.slice
    End Function

    Protected Overrides Function maxSupportVersion() As String
        Return "0"
    End Function

    Protected Overrides Function minSupportVersion() As String
        Return "0"
    End Function

    Protected Overrides Function modifyImpl(ByVal atom As atom, ByVal buff As bytes) As Boolean
        assert(False, "do not support modify in one slice.")
        Return False
    End Function

    Protected Overrides Function readImpl(ByVal atom As atom, ByRef buff As bytes) As Boolean
        buff.size = atom.valuelength
        stream().Position = atom.valuestart
        Dim readcount As Int32
        readcount = stream().Read(+buff, 0, atom.valuelength)
        If readcount <> atom.valuelength Then
            raiseError("cannot read enough value from file " + filename() + ", invalid slice file", _
                       errorHandle.errorType.exclamation)
            Return False
        Else
            Return True
        End If
    End Function

    Protected Overrides Function readIndex(ByRef key As String, ByRef atom As atom, ByVal lastpos As UInt64) As Boolean
        atom = New atom()
        atom.start = lastpos
        If binaryReaderHelper.readString(reader(), key) AndAlso _
           binaryReaderHelper.readUInt64(reader(), atom.valuelength) Then
            atom.valuestart = stream().Position()
            stream().Position() += atom.valuelength
            Return True
        Else
            Return False
        End If
    End Function

    Protected Overrides Function retireImpl() As Boolean
        Return create_empty_slice()
    End Function

    Protected Overrides Function sizeofImpl(ByVal atom As atom, ByRef size As UInt64) As Boolean
        size = atom.valuelength
        Return True
    End Function

    Protected Overrides Function version() As String
        Return "0"
    End Function

    Protected Overrides Function writeImpl(ByVal key As String, ByVal atom As atom, ByVal buff As bytes) As Boolean
        atom.valuelength = buff.size()
        stream().Position() = stream().Length()
        atom.start = stream().Position()
        writer.Write(key)
        writer.Write(Convert.ToUInt64(buff.size()))
        atom.valuestart = writer.BaseStream.Position()
        writer.Write(+buff)
        Return True
    End Function
End Class
